package com.cn.cash.baselib.retrofit;


import com.cn.cash.baselib.BaseManager;
import com.cn.cash.baselib.R;
import com.cn.cash.baselib.util.ToastUtil;
import com.cn.cash.baselib.util.CNUtil;
import com.cn.cash.baselib.util.ValidatorUtil;

import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Call;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import retrofit2.HttpException;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

/**
 * Created by CN on 2018-3-13.
 */

public class RetrofitManager {
    private static long TIMEOUT = 12 * 1000;
    private static RetrofitManager INSTANCE;
    private static Map<String, List<Disposable>> disposableMap;

    private static Map<String, Retrofit> retrofitMap;
    private OkHttpClient okHttpClient;
    public static final int SUCCESS_CODE = 200;
    public static final int ERROR_SERVER_EXCEPTION = 1000;
    public static final int ERROR_NET_FAILED = 1001;

    private RetrofitManager() {
        disposableMap = new HashMap<>();
        retrofitMap = new HashMap<>();
    }

    public static RetrofitManager getInstance() {
        if (INSTANCE == null) {
            synchronized (RetrofitManager.class) {
                if (INSTANCE == null) {
                    INSTANCE = new RetrofitManager();
                }
            }
        }
        return INSTANCE;
    }

    public Retrofit getRetrofit(String service) {
        return getRetrofit(service, null);
    }

    public Retrofit getRetrofit(String service, Interceptor interceptor) {
        Retrofit retrofit = retrofitMap.get(service);
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .client(getOkInstance(interceptor))//设置 HTTP Client  用于请求的连接
                    .addConverterFactory(ScalarsConverterFactory.create())   //字符串转换器
//                    .addConverterFactory(GsonConverterFactory.create())//json转换器
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .baseUrl(service)//请求的父目录
                    .build();
            retrofitMap.put(service, retrofit);
        }
        return retrofit;
    }

    public void request(Observable observable, String tag, RetrofitResponseListener responseListener) {
        request(observable, tag, responseListener, true);
    }

    public void request(Observable observable, final String tag, final RetrofitResponseListener responseListener, final boolean isShowErrorToast) {
        observable.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<String>() {

            private Disposable disposable;

            @Override
            public void onSubscribe(Disposable d) {
                disposable = d;
                if (tag != null) {
                    List<Disposable> disposableList = disposableMap.get(tag);
                    if (disposableList == null) {
                        disposableList = new ArrayList<>();
                    }
                    disposableList.add(disposable);
                    disposableMap.put(tag, disposableList);
                }
            }

            @Override
            public void onNext(String result) {
                CNUtil.log("请求成功:" + result);
                if (responseListener != null) {
                    responseListener.onSuccess(result);
                }
            }

            @Override
            public void onError(Throwable e) {
                int errorCode = 0;
                String errorMsg = null;
                if (e instanceof HttpException) {
                    HttpException httpException = ((HttpException) e);
                    errorCode = httpException.code();
                    errorMsg = httpException.message();
                }
                if (isShowErrorToast) {
                    ToastUtil.showLong(BaseManager.getApplication().getString(R.string.error_net_work));
                }
                errorCode = errorCode != 0 ? errorCode : ERROR_NET_FAILED;
                errorMsg = ValidatorUtil.isValidString(errorMsg) ? errorMsg : e.getMessage();
                CNUtil.log("请求失败errorCode:" + errorCode + "|errorMsg:" + errorMsg);
                if (responseListener != null) {
                    responseListener.onNetError(errorCode, errorMsg);
                }
                removeDisposableWithTag(tag, disposable);
            }

            @Override
            public void onComplete() {
                CNUtil.log("======请求结束======");
                removeDisposableWithTag(tag, disposable);
            }
        });

    }

    private void removeDisposableWithTag(String tag, Disposable disposable) {
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
        if (tag != null && disposableMap != null) {
            List<Disposable> disposableList = disposableMap.get(tag);
            if (disposableList != null) {
                disposableList.remove(disposable);
            }
        }
    }

    //撤销请求响应
    public void cancelDisposable(String tag) {
        if (tag != null && disposableMap != null) {
            List<Disposable> disposableList = disposableMap.get(tag);
            if (ValidatorUtil.isValidList(disposableList)) {
                for (Disposable disposable : disposableList) {
                    if (disposable != null && !disposable.isDisposed()) {
                        disposable.dispose();
                    }
                }
                disposableList.clear();
                disposableMap.remove(tag);
            }
        }
    }

    //撤销请求响应
    public void cancelAllDisposable() {
        if (disposableMap != null && !disposableMap.isEmpty()) {
            Iterator<String> iterator = disposableMap.keySet().iterator();
            if (iterator.hasNext()) {
                cancelDisposable(iterator.next());
            }
        }
        disposableMap.clear();
    }

    public OkHttpClient getOkInstance(Interceptor interceptor) {
        if (okHttpClient == null) {
            synchronized (OkHttpClient.class) {
                if (okHttpClient == null) {
                    OkHttpClient.Builder builder;
                    try {
                        final TrustManager[] trustAllCerts = new TrustManager[]{
                                new X509TrustManager() {
                                    @Override
                                    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                                    }

                                    @Override
                                    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
                                    }

                                    @Override
                                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                                        return new java.security.cert.X509Certificate[]{};
                                    }
                                }
                        };
                        // Install the all-trusting trust manager
                        final SSLContext sslContext = SSLContext.getInstance("SSL");
                        sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
                        builder = new OkHttpClient.Builder().readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                                .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                                .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                                .sslSocketFactory(sslSocketFactory);
                        if (interceptor != null) {
                            builder.addInterceptor(interceptor);
                        } else {
                            builder.addInterceptor(new CNRequestInterceptor());
                        }
                        okHttpClient = builder.build();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    if (okHttpClient == null) {
                        builder = new OkHttpClient.Builder().readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                                .writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
                                .connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS);
                        if (interceptor != null) {
                            builder.addInterceptor(interceptor);
                        } else {
                            builder.addInterceptor(new CNRequestInterceptor());
                        }
                        okHttpClient = builder.build();
                    }
                }
            }
        }
        return okHttpClient;
    }

    public static void setTIMEOUT(long TIMEOUT) {
        RetrofitManager.TIMEOUT = TIMEOUT;
    }

    public void removeInterceptor(Interceptor interceptor) {
        if (okHttpClient != null) {
            okHttpClient.interceptors().remove(interceptor);
        }
    }

    public void removeAllInterceptor() {
        if (okHttpClient != null) {
            okHttpClient.interceptors().clear();
        }
    }

    /**
     * 通过tag撤销请求
     */
    public void cancelRequestByTag(String tag) {
        if (tag == null || okHttpClient == null)
            return;
        for (Call call : okHttpClient.dispatcher().queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                CNUtil.log("cancelQueuedCalls:" + tag);
                call.cancel();
            }
        }
        for (Call call : okHttpClient.dispatcher().runningCalls()) {
            if (tag.equals(call.request().tag())) {
                CNUtil.log("cancelRunningCalls:" + tag);
                call.cancel();
            }
        }
    }

    public void cancelAllRequest() {
        if (okHttpClient == null) {
            return;
        }
        for (Call call : okHttpClient.dispatcher().queuedCalls()) {
            call.cancel();
        }
        for (Call call : okHttpClient.dispatcher().runningCalls()) {
            call.cancel();
        }
    }
}
